﻿using LogSystem;
using Modules.Chat;
using OWL.Rendering.HRP;
using ParadoxNotion;
using SuperSDKV4.Classes;
using System;
using System.Collections;
using com.yoozoo.gta.Extension.UGUI.ScreenOrientationEx;
using Neonagee.LocalPreferences;
using UnityEngine;
using XLua;
using Yoozoo.Core.Common;
using Yoozoo.Framework.Core;
using Yoozoo.Framework.Managers;
using Yoozoo.Framework.Network.Helpers;
using Yoozoo.Gameplay.City;
using Yoozoo.Gameplay.Common;
using Yoozoo.Gameplay.Liberty.PlayerController;
using Yoozoo.Gameplay.Modules.Update;
using Yoozoo.Gameplay.RTS;
using Yoozoo.Gta.Common;
using Yoozoo.Gta.ProjBuilder;
using Yoozoo.Manager;
using Yoozoo.Managers.ResourceManagement;
using Yoozoo.Managers.ResourceManagerV2.Framework.Resource;
using Yoozoo.Mars.Got;
using Yoozoo.Mars.SDK;
using Yoozoo.Modules.Download;
using Yoozoo.Modules.Entry;
using Yoozoo.Modules.Update;
using ZString;
using GameHelper = Yoozoo.Modules.Update.GameHelper;

namespace Yoozoo.Gameplay
{
    using Gameplay.Managers;
    using Yoozoo.Managers.ResourceManagerV2.Runtime;

    public class GTAGameStart : UMTLauncher
    {
        #region public member

        public static bool m_isLog;

        public static bool IsDebug;

        public int emmyLuaPort = 9966;

        public GameObject[] ResourceManagers;

        public UpdateComponent m_updateComponent;

        private static GTAGameStart instance;
        #endregion

        #region private member

        //LuaManager m_luaManager;
        Tools.Debugger.Log m_log;

        public static GameObject TaskSchedule { get; set; }
        
        public static Coroutine_Runner TaskScheduleCoroutineRunner { get; set; }

        public static EventSystem eventManager { get; private set; }
        
        private ResLoader _resLoader;

        private SDKManager _sdkManager;
        private float lastFocusTime;
        private bool isInitializeResourceModuleOnStart;

        private static event Action<bool> luaFocusEventHandler;
        private static event Action<bool> luaPauseEventHandler;
        private static event Action luaApplicationQuitEventHandler;
        private static event Action luaEscapeEventHandler;

        #endregion

        #region unity methods

        public override void UMTAwake()
        {
            instance = this;

#if UNITY_EDITOR
            SingletonSetting.ApplicationQuitting = false;
            ResourceV2Entry.Clear();
            Tools.Debugger.Log.Init();
#endif
            try
            {
                m_log = Tools.Debugger.Log.GetInstance();
                if (!Tools.Debugger.Log.isInited)
                {
                    m_log.Initialize();
                }
                
            }
            catch (Exception e)
            {
                Debug.LogError("Initialize Log failed " + e.ToString());
            }

           
            InitLoadingUIInternal();
            m_updateComponent?.Active();
            if (AppConfig.IsSDK && UMTResource.Initializated)
            {
                m_updateComponent.OnUpdateVersion();
                m_updateComponent.m_txtTip.text = GTAHotUpdateLangConfig.GetLang("hotupdate_init_module");
            }

            using (zstring.Block())
            {
            }

            EventTracingManager.GetInstance().Start();
            EventTracingManager.GetInstance().Trace(E_TRACING_ID.ON_UNITY_INIT_OK);
            DebugAgent.GetInstance().Initialize();
            if (GameHelper.AotCodeVersion > 20241021)
            {
                printBaseInfoLog();
            }
#if UNITY_ANDROID || UNITY_IPHONE
                //禁止手机黑屏
                Screen.sleepTimeout = SleepTimeout.NeverSleep;
            
#endif
            Application.runInBackground = true;
          
            Application.quitting += () => { SingletonSetting.ApplicationQuitting = true;};
            
            

#if !UNITY_EDITOR
            EventTracingManager.GetInstance().Trace(E_TRACING_ID.ON_BUGLY_INIT_OK);
#endif
           
            SetResolution();
            
#if !UNITY_EDITOR
            luaAB = true;
            m_isLog = AppConfig.IsLog;
#else
            m_isLog = true;
#endif

            isInitializeResourceModuleOnStart = true;
            
            //sdk初始化
            if (AppConfig.IsSDK)
            {
                bool isCallInit;
                if (GameHelper.AotCodeVersion >= 20241018)
                {
                    isCallInit = IsCallSDKInitFunc();
                }
                else
                {
                    isCallInit = Mars.SDK.SDKPlatform.GetInstance().SuperSdkInitSuccess;
                }

                if (!isCallInit)
                {
                    Debug.Log("SuperSDK初始化");

#if UNITY_STANDALONE_WIN
                    // PCSDK 需要等初始化完毕才能开始后续流程，否则很多数据拿不到
                    isInitializeResourceModuleOnStart = false;
#endif

                    SDKPlatform.GetInstance().InitSuccessCallBack += OnSuperSDKInitSuccessCallBack;
                    Mars.SDK.SDKAgent.GetInstance().OnSuperSDKInit(gameObject.name);

                }

            }

#if GT
            Debug.Log("GT初始化");
            GT.Init();
#endif

#if UWA && !UNITY_EDITOR 
            UWAEngine.StaticInit();
#endif
 
            
            UIBinder.Register();
            if (!m_isLog)
            {
                Debug.LogLevel = LogLevelType.Always;
            }


            //networkManager = NetworkManager.GetInstance();
            //networkManager.Initialize();

            if (UMTResource.Initializated)
            {
                if (ResourceManagers != null)
                {
                    foreach (var resourceManager in ResourceManagers)
                    {
                        Destroy(resourceManager);
                    }
                }
            }
            else
            {
                // 编辑器下ResourceMode由 ResourceUserSettings.ResourceMode 的控制
                int resourceMode;

                if (AppConfig.IsUpdateResource)
                {
                    resourceMode = AppConfig.IsUpdateWhilePlaying ? (int)ResourceMode.UpdatableWhilePlaying : (int)ResourceMode.Updatable;
                }
                else
                {
                    resourceMode = (int)ResourceMode.Package;
                }

#if UNITY_EDITOR
                resourceMode = (int)ResourceUserSettings.ResourceMode;
#endif
                if (resourceMode > 0)
                {
                    resourceMode = resourceMode - 1;
                }

                if (ResourceManagers != null && ResourceManagers.Length > resourceMode)
                {
                    var resourceManager = ResourceManagers[resourceMode];
                    if (resourceManager != null)
                        resourceManager.SetActive(true);
                }
            }
        }

        private void printBaseInfoLog()
        {
            UnityEngine.Debug.Log($"{Application.platform}  aot:{GameHelper.AotCodeVersion} rv:{GameHelper.isReviewVersion}  v:{GameHelper.GetAppVersion()}.{GameHelper.GetResVersion()}  appconfig:{AppConfig.Version}  screen:{Screen.width}x{Screen.height} resolution:{DeviceReportInfo.resolution}  dpi:{Screen.dpi}  {Application.systemLanguage} {DeviceReportInfo.resolution}");
        }

        private bool IsCallSDKInitFunc()
        {
#if UNITY_ANDROID || UNITY_IPHONE
            return Mars.SDK.SDKPlatform.GetInstance().IsCallInit();
#else
            return Mars.SDK.SDKPlatform.GetInstance().SuperSdkInitSuccess;
#endif
        }
        private static void SetResolution()
        {
            // PC设置分辨率
            GameHelper.SetResolution();
        }
        
        public override IEnumerator UMTStart()
        {
            EventTracingManager.GetInstance().Trace(E_TRACING_ID.ON_START_GAME);
            AddSupportComponent();
            CSharpNetWorkReciever.GetInstance().Initialize();
            yield return InitResource();
        }

        public IEnumerator InitResource()
        {
            if (UMTResource.Initializated)
            {
                yield return StartCoroutine(TodoComplete());
            }
            else
            {
                yield return new WaitForEndOfFrame();
                if (isInitializeResourceModuleOnStart)
                {
                    UMTResource.Initialize();
                    UMTResource.HotUpdateStart();
                }
            }
        }

        private void AddSupportComponent()
        {
            Debug.Log("加入支持组件");
            // TODO
            TaskSchedule = new GameObject("TaskSchedule");
            TaskScheduleCoroutineRunner = TaskSchedule.AddComponent<Coroutine_Runner>();
            DontDestroyOnLoad(TaskSchedule);

#if EventTrace
            this.AddComponent<HitPoint.PerformanceHitPointManager>();
            this.AddComponent<Yoozoo.Modules.TraceEvent.ApmReportManager>();
#endif

#if PocoSDK_Enabled 
            if (Debug.isDebugBuild)
            {
                GameObject pocoSDK = GameObject.Find("Plugin/PocoSDK");
                pocoSDK.AddComponent<PocoManager>();
            }
#endif
            
            
        }

        public override void UMTUpdate()
        {
            m_luaManager?.Update();
            // networkManager.Update();
            // touchManager?.Update();
            if (LuaManager.IsLuaStarted())
            {
                //CSInputMgr.Update(LuaManager.mainState);
                if (Input.GetKey(KeyCode.Escape))
                {
                    luaEscapeEventHandler?.Invoke();
                }
            }
        }

        public override void UMTDestroy()
        {
            if (_resLoader != null)
            {
                _resLoader.Recycle2Cache();
                _resLoader = null;
            }

            if (m_luaManager != null)
            {
                m_luaManager.Dispose();
                m_luaManager = null;
            }
            
        }

        #endregion

        #region private methods
        

#if !NoTest_Opt
        public override void OnUpdateComplete()
        {
            
            UMTResource.InitPool();
            UMTResource.PreloadFileSystems();

            SDKPlatform.GetInstance().InitSuccessCallBack -= OnSuperSDKInitSuccessCallBack;
            CommonDialogHelper.Instance.OnResourceUpdateSuccess();

            StartCoroutine(TodoComplete());
        }

        /// <summary>
        /// SuperSDK初始化完成
        /// </summary>
        private void OnSuperSDKInitSuccessCallBack()
        {
            
            // PCSDK 需要等初始化完毕才能开始后续流程，否则很多数据拿不到
            if (!isInitializeResourceModuleOnStart)
            {
                UMTResource.Initialize();
                UMTResource.HotUpdateStart();
            }
        }

        #if UNITY_EDITOR
        private GpuHudFacade gpuHudFacade;
        #endif

        private IEnumerator TodoComplete()
        {
#if UNITY_EDITOR
            // 收集加载的资源，这段要放在最前面
            var collector = GetComponent<SubPackageCollector>();
            if (collector)
            {
                collector.Collect();
            }
#endif
            
            var gpuHudFacade = GpuHudFacade.GetInstance("GpuHud");
            gpuHudFacade.Initialize();
            #if UNITY_EDITOR
            this.gpuHudFacade = gpuHudFacade;
            #endif

            InitObjectUtils();

            yield return null;

            // SDK模式不弹登录页面，先别关闭文本显示，会看起来像卡住一样
            if (!AppConfig.IsSDK)
                m_updateComponent?.OnUpdateComplete();


            
            ClientReportConfig.Init();

            var sceneRoot = new GameObject("SceneRoot");
            // 初始化 RenderSceneManager 和 QualityManager
            var qualityManagerPath = "Assets/ResourcesAssets/Persistent/QualityManager.prefab";
            UMTResource.LoadAssetRapid(qualityManagerPath, (assetName, asset, duration, data) =>
            {
                QualityHelper.LoadPcSetting();
                
                var o = asset as GameObject;
                QualityManager.Inst = Instantiate(o).GetComponent<QualityManager>();
                DontDestroyOnLoad(QualityManager.Inst.gameObject);
            });

            var renderScenePath = "Assets/ResourcesAssets/Persistent/RenderSceneManager.prefab";
            UMTResource.LoadAssetRapid(renderScenePath, (assetName, asset, duration, data) =>
            {
                var o = asset as GameObject;
                Instantiate(o).GetComponent<HRenderSceneManager>();
                DontDestroyOnLoad(HRenderSceneManager.Inst.gameObject);
            });


            // DeviceAgent需要QualityManager和HRenderSceneManager初始化
            // LuaInit()需要DeviceAgent初始化
            while (QualityManager.Inst == null || gpuHudFacade.Settings == null || HRenderSceneManager.Inst == null)
            {
                yield return null;
            }

            //画质分级初始化
            DeviceAgent.Instance.InitDevicesGrading();
            DependencyInjection.DeviceAgent = DeviceAgent.Instance;
            DependencyInjection.InjectGetCurrentQuality(() => DeviceQuality.Instance.GetCurrentQuality().ToString());

            // 等设备信息读取完毕
            while (!DevicesGrading.Instance.IsInitialized)
            {
                yield return null;
            }

            // 边玩边下也按设备分级
            if (ResourceUpdateHelper.NeedDownloadWhilePlaying)
                DownloadWhilePlayingManager.Instance.Initialize();

#if !UNITY_EDITOR
            //初始化
            ShaderMgr.LoadLoadingVariantCollectionsShaders(() =>
            {
#endif
                EventTracingManager.GetInstance().Trace(E_TRACING_ID.ON_SHADER_WARMUP);
#if UNITY_EDITOR
                FrameManager.Initialize();
#endif
            
                LuaInit();

                // 多国语的初始化(依赖Lua初始化)
                LocalizationManager.GetInstance().Initialize();
                // 按钮组件的初始化(依赖AudioManager，音频初始化依赖于多语言)
                GuiManager.Initialize();
                eventManager = new EventSystem();
                //对象池初始化
                PoolMgr.Init();
                //启动
                _sdkManager = SDKManager.GetInstance();
                _sdkManager.Init(gameObject);

                EmojiCreator.GetInstance().Init();

                var gpuSkinningRoot = new GameObject("GpuSkinning", typeof(GpuSkinningHandle));
                gpuSkinningRoot.transform.SetParent(transform);

                if (GameHelper.AotCodeVersion >= 20241021)
                {
                    LogDeviceModel();
                }

                // 读取黑名单
                string deviceNames = ResidentHandler.Inst.GetFunction("G_GameHelper.getDeviceNames").Func<int, string>(0);
                DeviceAgent.Instance.SetDeviceNames(deviceNames);

                // 设置白名单
                bool inWhiteList = LocalPrefs.GetBool("InWhiteList", false);
                DeviceAgent.Instance.SetInWhiteList(inWhiteList);

#if !UNITY_EDITOR
            });
#endif

                //LuaInit();

                //// 多国语的初始化(依赖Lua初始化)
                //LocalizationManager.GetInstance().Initialize();
                //// 按钮组件的初始化(依赖AudioManager，音频初始化依赖于多语言)
                //GuiManager.GetInstance().Initialize();
                //eventManager = new EventSystem();
                ////对象池初始化
                //PoolMgr.Init();
                ////启动
                //_sdkManager = SDKManager.GetInstance();
                //_sdkManager.Init(gameObject);

                //EmojiCreator.GetInstance().Init();
        }
#endif

        private void LogDeviceModel()
        {
            CrashSightAgent.PrintLog(CSLogSeverity.LogInfo, "DeviceReportInfo.Model: {0}", DeviceReportInfo.model);
            CrashSightAgent.PrintLog(CSLogSeverity.LogInfo, "SystemInfo.deviceModel: {0}", SystemInfo.deviceModel);
            CrashSightAgent.PrintLog(CSLogSeverity.LogInfo, "SystemInfo.deviceName: {0}", SystemInfo.deviceName);
        }
    
        private void InitObjectUtils()
        {
            if (ObjectUtils.Comparer<ControlMode>.EqualsFunction == null)
                ObjectUtils.Comparer<ControlMode>.EqualsFunction = ControlModeEquals;
        }

        private static bool ControlModeEquals(ControlMode a, ControlMode b)
        {
            return a == b;
        }

        private void LuaInit()
        {
            m_luaManager = LuaManager.GetInstance();
            m_luaManager.abMode = luaAB;
            m_luaManager.Initialize();
            m_luaManager.emmyLuaDebuggerAutoLaunch = emmyLuaDebuggerAutoLaunch;
            m_luaManager.emmyLuaPort = emmyLuaPort;
            gameObject.AddComponent<LuaLooper>().luaState = LuaManager.mainState;
            EventTracingManager.GetInstance().Trace(E_TRACING_ID.ON_LUA_INIT);
            SDKPlatform.GetInstance().SuperSdkTrackLoadLanguage();
            m_luaManager.Start(luaMainFunc);

            DependencyInjection.LuaFuncStr = (tableName, functionName) =>
            {
                var luaTable = LuaManager.mainState.GetLuaTable(tableName);
                var luaFunction = luaTable?.GetLuaFunction(functionName);
                var result = luaFunction?.Call();
                return result?.GetValue(0).ToString() ?? "";
            };

            DependencyInjection.LuaAction = (functionName, args) =>
            {
                var function = LuaManager.mainState.GetFunction(functionName);
                var newArgs = new object[args.Length + 1];
                newArgs[0] = null;
                for (var i = 0; i < args.Length; i++)
                {
                    newArgs[i + 1] = args[i];
                }

                function?.Call(newArgs, null);
            };

            DependencyInjection.LuaAction("G_LoginHelper.setMaintenanceJson", ResourceUpdateHelper.VersionAndMaintenanceJson);
            DependencyInjection.LuaAction("setCustomServiceUrl", ResourceUpdateHelper.CustomServiceUrl);
            SDKManager.SuperSDKLoginSuccessCallback();

            InjectDownloadEvents();

            if (GameHelper.AotCodeVersion >= 20240229)
            {
                InjectLoadingEvents();
            }
        }

        private void InjectLoadingEvents()
        {
            UMTResource.DispatchLoadResourceHanging = () =>
            {
                ResidentHandler.Inst.GetFunction("G_GameHelper.OnLoadResourceHanging").Action();
            };
        }


        private void InjectDownloadEvents()
        {
            UMTResource.DispatchDownloadFinish = () =>
            {
                ResidentHandler.Inst.GetFunction("G_GameHelper.OnDownloadFinish").Action();
                if (DownloadManager.p_IsInitialize)
                    DownloadManager.Instance.Resume();

                if (GameHelper.AotCodeVersion >= 20240920)
                {
                    TraceDownloadLoading("转圈结束");
                }
            };

            UMTResource.DispatchDownloadStart = (tasks) =>
            {
                ResidentHandler.Inst.GetFunction("G_GameHelper.OnDownloadStart").Action(tasks);
                if (DownloadManager.p_IsInitialize)
                    DownloadManager.Instance.Pause();

                if (GameHelper.AotCodeVersion >= 20240920)
                {
                    TraceDownloadLoading("转圈开始");
                }
            };

            if (GameHelper.AotCodeVersion >= 20240920)
            {
                InjectNewDownloadEvents();
            }
        }

        private void TraceDownloadLoading(string actionName)
        {
            EventTracingManager.GetInstance().ClientReportDownloadLoading(actionName);
        }

        private void InjectNewDownloadEvents()
        {
            var collector = GetComponent<SubPackageCollector>();
            UMTResource.OnAddDownload = (resourceName, size) =>
            {
                string fileName = System.IO.Path.GetFileName(resourceName);
                EventTracingManager.GetInstance().ClientReportDownloadStart(fileName);
                collector?.AddResourceName(resourceName);
            };

            UMTResource.OnDownloadSuccess = (resourceName) =>
            {
                string fileName = System.IO.Path.GetFileName(resourceName);
                EventTracingManager.GetInstance().ClientReportDownloadSuccess(fileName);
            };

            UMTResource.OnDownloadFailed = (resourceName) =>
            {
                string fileName = System.IO.Path.GetFileName(resourceName);
                EventTracingManager.GetInstance().ClientReportDownloadFailed(fileName);
            };
        }

        private void OnApplicationFocus(bool hasFocus)
        {
#if !UNITY_EDITOR
             luaFocusEventHandler?.Invoke(hasFocus);
             var _ct = TimeUtils.GetClientTickTime();
             Debug.Log("OnApplicationFocus :"+_ct);
             if (this.lastFocusTime != 0 && hasFocus)
             {
                 var durt = _ct - this.lastFocusTime;
                 if (durt > 3)
                 {
                     Debug.Log($"OnApplicationFocus : 切换时间超过 {durt}");
                     //luaPauseEventHandler?.Invoke(hasFocus);  //为了在Editor下测试暂停逻辑
                 }
             }
           
             this.lastFocusTime = _ct;
#endif

        }
        private void OnApplicationPause(bool pauseStatus)
        {
#if !UNITY_EDITOR
            luaPauseEventHandler?.Invoke(pauseStatus);
            Debug.Log("OnApplicationPause: pauseStatus:"+pauseStatus+"  time:"+TimeUtils.GetClientTickTime());
#endif
        }
        
        private void OnApplicationQuit()
        {
            luaApplicationQuitEventHandler?.Invoke();
#if UNITY_EDITOR
            if (gpuHudFacade)
            {
                gpuHudFacade.Dispose();
                gpuHudFacade = null;
            }
            DeviceQuality.Instance.ClearAllActions();
            CityRealAiManager.GetInstance().DisposeExternal();
            TaskScheduleCoroutineRunner = null;
#endif
        }
#endregion

        public static void AddLuaPauseEventHandler(Action<bool> action)
        {
            luaPauseEventHandler += action;
        }

        
        public static void AddApplicationQuitEventHandler(Action action)
        {
            luaApplicationQuitEventHandler += action;
        }


        public static void AddLuaFocusEventHandler(Action<bool> action)
        {
            luaFocusEventHandler += action;
        }

        public static void AddLuaEscapeEventHandler(Action action)
        {
            luaEscapeEventHandler += action;
        }
        
        public static void RemoveLuaPauseEventHandler(Action<bool> action)
        {
            luaPauseEventHandler -= action;
        }
        
        public static void RemoveApplicationQuitEventHandler(Action action)
        {
            luaApplicationQuitEventHandler -= action;
        }
        
        public static void RemoveLuaFocusEventHandler(Action<bool> action)
        {
            luaFocusEventHandler -= action;
        }

        public static void RemoveLuaEscapeEventHandler(Action action)
        {
            luaEscapeEventHandler -= action;
        }

        //supersdk 回调
        public void CallBack(string msg)
        {
            Debug.Log("GTAGameStart callback bySupersdk: " + msg);
            AndroidCallSuperSDK.GetInstance().CallBack(msg);
        }

        /// <summary>
        /// 销毁LoadingUI
        /// LoadingUI在资源更新的时候使用，此时资源管理器没有初始化完成，所以无法读取AssetBundle内的资源
        /// 一旦资源管理器初始化完毕，就销毁UI和背景图，释放内存
        /// </summary>
        private void DestroyLoadingUIInternal()
        {
            if (m_updateComponent)
            {
                m_updateComponent.Deactive();
                m_updateComponent = null;
            }
        }
        /// <summary>
        /// 加载创建LoadingUI
        /// LoadingUI在资源更新的时候使用，此时相关dll还未加载，所以横竖屏无法使用，这里用了两个prefab，按照横竖屏加载
        /// 
        /// </summary>
        private void InitLoadingUIInternal()
        {
            if (Screen.width > Screen.height)
            {
                var loadingUIAsset = Resources.Load<GameObject>("Prefabs/UI/LoadingUI");
                if (loadingUIAsset)
                {
                    var root = GameObject.Find("UIRoot/RootCanvas");
                    var loadingUI  = Instantiate<GameObject>(loadingUIAsset,root.transform);
                    this.m_updateComponent = loadingUI.transform.GetComponent<UpdateComponent>();
                }
            }
            else
            {
                var loadingUIAsset = Resources.Load<GameObject>("Prefabs/UI/LoadingUI_Portrait");
                if (loadingUIAsset)
                {
                    var root = GameObject.Find("UIRoot/RootCanvas");
                    var loadingUI  = Instantiate<GameObject>(loadingUIAsset,root.transform);
                    this.m_updateComponent = loadingUI.transform.GetComponent<UpdateComponent>();
                }
            }
        }
        public static void DestroyLoadingUI()
        {
            instance?.DestroyLoadingUIInternal();
        }
    }
}
